package fr.umlv.escapeir.painters;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.Stack;

import org.jbox2d.collision.AABB;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.IViewportTransform;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.OBBViewportTransform;
import org.jbox2d.common.Transform;
import org.jbox2d.common.Vec2;

public class WorldGraphics2D {
	
	private Graphics2D painter;
	private final IViewportTransform viewportTransform;
	private final Stack<Graphics2D> oldPainters;
	
	public WorldGraphics2D (int screenw, int screenh) {
		viewportTransform = new OBBViewportTransform();
		viewportTransform.setExtents(screenw, screenh);
		viewportTransform.setYFlip(true);
		oldPainters = new Stack<>();
	}
	
	public void drawRectWithImage (Vec2 topLeft, Vec2 bottomRight, Image img) {
		Vec2 orig = topLeft;
		Vec2 dst = bottomRight;
		Vec2 origScreen = new Vec2();
		Vec2 dstScreen = new Vec2();
		viewportTransform.getWorldVectorToScreen(orig, origScreen);
		viewportTransform.getWorldVectorToScreen(dst, dstScreen);
		
		painter.drawImage(img, MathUtils.round(origScreen.x),
				  MathUtils.round(origScreen.y),
				  MathUtils.round(dstScreen.x),
				  MathUtils.round(dstScreen.y),
				  0, 0, img.getWidth(null), img.getHeight(null), null);
	}
	
	public void drawCircleWithImage (CircleShape shape, Image img) {
		AABB aabb = new AABB();
		Transform t = new Transform();
		t.setIdentity();
		shape.computeAABB(aabb, t);
		drawRectWithImage(aabb.upperBound, aabb.lowerBound, img); 
	}
	
	public void fillShape (Shape shape) {
		switch(shape.getType()) {
			case POLYGON:
				PolygonShape pshape = (PolygonShape)shape;
				Vec2[] vertices = pshape.m_vertices;
				int vertexCount = pshape.getVertexCount();
				fillPolygon(vertices, vertexCount);
				break;
			case CIRCLE:
				CircleShape cshape = (CircleShape)shape;
				fillCircle(cshape.m_p, cshape.m_radius);
				break;
			default:
				break;
		}
	}
	
	public void fillPolygon(Vec2[] vertices, int count) {
		int xscreen[] = new int[count];
		int yscreen[] = new int[count];
		
		Vec2 vecScreen = new Vec2();
		for (int i = 0; i < count; i++) {
			viewportTransform.getWorldVectorToScreen(vertices[i], vecScreen);
			xscreen[i] = MathUtils.round(vecScreen.x);
			yscreen[i] = MathUtils.round(vecScreen.y);
		}
		painter.fillPolygon(xscreen, yscreen, count);
	}
	
	public void fillCircle(Vec2 vecOrigWorld, float radius) {
		Vec2 vecOrigScreen = new Vec2();
		viewportTransform.getWorldVectorToScreen(vecOrigWorld, vecOrigScreen);
		
		Vec2 vecDstWorld = new Vec2(vecOrigWorld.x+radius, vecOrigWorld.y);
		Vec2 vecDstScreen = new Vec2();
		viewportTransform.getWorldVectorToScreen(vecDstWorld, vecDstScreen);
		
		int radiusScreen = MathUtils.round(MathUtils.distance(vecOrigScreen, vecDstScreen));
		painter.fillOval(MathUtils.round(vecOrigScreen.x-radiusScreen), MathUtils.round(vecOrigScreen.y-radiusScreen), radiusScreen*2, radiusScreen*2);
	}
	
	public void drawImage (Image img, Vec2 orig, Vec2 dst) {
		Vec2 origScreen = new Vec2();
		Vec2 dstScreen = new Vec2();
		viewportTransform.getWorldVectorToScreen(orig, origScreen);
		viewportTransform.getWorldVectorToScreen(dst, dstScreen);
		
		painter.drawImage(img, MathUtils.round(origScreen.x), MathUtils.round(origScreen.y), MathUtils.round(dstScreen.x), MathUtils.round(dstScreen.y), 0, 0, img.getWidth(null), img.getHeight(null), null);
	}
	
	public void setPainter (Graphics2D painter) {
		this.painter = painter;
		oldPainters.clear();
	}
	
	public void translateFromWorld (Vec2 delta) {
		Vec2 res = new Vec2(0,0);
		viewportTransform.getWorldToScreen(delta, res);
		painter.translate(res.x, res.y);
	}
	
	public void rotate (float theta) {
		painter.rotate(theta);
	}
	
	public void save() {
		oldPainters.push(painter);
		painter = (Graphics2D)painter.create();
	}
	
	public void restore () {
		if (oldPainters.isEmpty()) return;
		painter.dispose();
		painter = oldPainters.pop();
	}

	public void setColor(Color color) {
		painter.setColor(color);
	}

}
